﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Timers;

namespace PmfWeb.Core.Pool
{
    ///<summary>
    /// 对象池
    ///</summary>
    public abstract class ObjectPool<T> where T : class 
    {
        /// <summary>
        /// 对象最后取出的时间
        /// </summary>
        private long _lastCheckOut = 0;

        /// <summary>
        /// 记录当前正在使用对象Hashtable
        /// </summary>
        private static Hashtable _hashlocked;
        /// <summary>
        /// 记录空闲的对象
        /// </summary>
        private static Hashtable _hashfree;
        /// <summary>
        /// 检查所有空闲及可用对象时间间隔：60秒(用于垃圾回收)
        /// </summary>
        private static long _checkObjectTime = 60*1000;

        static ObjectPool()
        {
            _hashlocked = Hashtable.Synchronized(new Hashtable());
            _hashfree = Hashtable.Synchronized(new Hashtable());
        }
        /// <summary>
        /// 创建新实例
        /// </summary>
        /// <returns></returns>
        protected abstract T Instance();
        /// <summary>
        /// 检查对象是否有效
        /// </summary>
        /// <param name="t">对象实例</param>
        /// <returns>是否有效</returns>
        protected abstract bool ValiDate(T t);

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="t"></param>
        protected abstract void Expire(T t);

        internal ObjectPool()
        {
            _lastCheckOut = DateTime.Now.Ticks;

            Timer timer = new Timer();
            timer.Interval = _checkObjectTime;
            timer.Enabled = true;
            timer.Elapsed += delegate
                                 {
                                     lock (this)
                                     {
                                         long longNow = DateTime.Now.Ticks;
                                         try
                                         {
                                             foreach (DictionaryEntry entry in _hashfree)
                                             {
                                                 T t = (T) entry.Key;
                                                 if (_checkObjectTime < (longNow - (long) _hashfree[t]))
                                                 {
                                                     _hashfree.Remove(t);
                                                     Expire(t);
                                                 }


                                             }
                                         }
                                         catch (Exception)
                                         {
                                             //throw;
                                         }
                                     }
                                 };
        }

        internal T GetObjectByPool()
        {
            long longNow = DateTime.Now.Ticks;
            _lastCheckOut = longNow;
            T t;

            lock (this)
            {
                try
                {
                    foreach (DictionaryEntry entry in _hashlocked)
                    {
                        t = (T) entry.Key;
                        if(ValiDate(t))
                        {
                            _hashfree.Remove(t);
                            _hashlocked.Add(t, longNow);
                            return t;
                        }
                        _hashfree.Remove(t);
                        Expire(t);
                    }
                }
                catch (Exception)
                {
                }
                t = Instance();
                _hashlocked.Add(t,longNow);
            }
            return t;
        }

       internal void ReturnObjectToPool(T t)
       {
           if(!Object.Equals(null, t))
           {
               lock (this)
               {
                   _hashfree.Remove(t);
                   _hashfree.Add(t, DateTime.Now.Ticks);
               }
           }
       }
    }
}
